#ifndef KERNEL_H
#define KERNEL_H

#include <deque>
#include <map>
#include <list>
#include <vector>

#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>

#include "core/logger.h"

using std::list;
using std::deque;

using std::vector;

using boost::shared_ptr;

namespace engine {

	namespace core {

		class Engine;
		class Process;

		struct Message;

		using std::map;
		
		class Kernel : boost::noncopyable {
			private:
				typedef deque< shared_ptr<Message> > MessageQueue;
				typedef map<uint, shared_ptr<Process> > ProcessLookup;
                typedef list<shared_ptr<Process> > ProcessList;

				typedef map<uint, vector<shared_ptr<Process> > > MessageLookup;

				list< shared_ptr<Process> > m_List;
				deque< shared_ptr<Message> > m_MessageList;

				Engine* m_ParentEngine;
				
                MessageLookup   m_Listeners;
                ProcessLookup   m_ProcessesByID;
                ProcessList     m_ProcessList;

				vector<uint>	m_ProcessesToKill;
				
				///Just generates a new ID for each process
				uint generatePID() {
					static uint s_PID = 1000;
					return s_PID++;
				}

				void appendToMessageList(const MessageQueue& queue) {
					if (queue.empty())
						return;
						
					Logger::getLogger("kernel")->debug("We have some messages!");
					
					/*for (MessageQueue::const_iterator it = queue.begin(); it != queue.end(); ++it) {
						m_MessageList.push_back((*it));
					}*/
					m_MessageList.insert(m_MessageList.end(),
											queue.begin(),
											queue.end());
				}

				
				void processMessages();
				bool processSystemEvents();
				
				void processKernelMessage(shared_ptr<Message> msg);
				shared_ptr<Process> findProcessByID(uint PID);
				
				void killAllProcesses();
			public:
				Kernel();
				~Kernel();

				int run();
				///Adds a process and returns the generated PID
				uint addProcess(shared_ptr<Process> newProc);
				void removeProcess(uint PID);

				void registerListener(uint msgID, uint PID);

				float getDT() { return 0.0f; }
				
				void setParentEngine(Engine* parent);
		};
	}
}

#endif
